#!/usr/bin/env python

'''
Signal/callback management. 
'''

class EventManager(object):
    '''
    Base class to add signal/callback management to sub-class.
    '''
    _callbacks = {}
    
    def __init__(self, events):
        '''
        Initialize an C{EventManager}  with the the events in C{events}.
        
        @param  events: List of events that can be subscribed to.
        @type   events: List
        '''
        for e in events: self._callbacks[e] = []
    
    def emit(self, event, *args):
        '''
        Call each of the subscribed callback functions.
        
        @param  event:  The event to emit.
        @type   event:  String
        @param  args:   Additional positional args to pass to callbacks.
        @type   args:   List
        '''
        for cb in self._callbacks[event]:
            nargs = args + cb[1]
            cb[0](*nargs, **cb[2])
    
    def connect(self, event, func, *args, **kwargs):
        '''
        Subscribe to event using callback C{func} with the arguments C{*args}
        and C{**kwargs}.
        
        @param  event:  Event to subscribe to.
        @type   event:  String
        @param  func:   Function to call when signal is emitted.
        @type   func:   Function
        @param  args:   Positional arguments to call C{func} with.
        @type   args:   List
        @param  kwargs: Keywords arguments to call C{func} with.
        @type   kwargs: Dictionary
        '''
        self._callbacks[event].append((func, args, kwargs))
    
    def disconnect(self, event, func):
        '''
        Unsubscribe the callback functions C{func} from the event C{event}.
        
        @param  event:  Event to unsubscribe from.
        @type   event:  String
        @param  func:   Function to unsubscribe.
        @type   func:   Function
        '''
        for cb in self._callbacks[event]:
            if cb[0] == func: self._callbacks[event].remove(cb)  

#-------------------------------------------------------------------------------
# test script
if __name__ == '__main__':
    
    def func(name, *args, **kwargs):
        print '  -> %s called' % name
        
    class TestEventManager(EventManager): pass
    events = ['test_%d' % x for x in range(10)]
    em = TestEventManager(events)
    print 'connecting events...'
    for e in events: em.connect(e, func, e)
    print 'emitting events...'
    for e in events: em.emit(e)
    print 'disconnecting events...'
    for e in events: em.disconnect(e, func)
    
    
